// xmltools.cpp
//
// XML tools

#include "xmlTools.h"

namespace simple{
    //
    // XMLTools
    //
    XMLTools::XMLTools () {}


    XMLTools::XMLTools (const std::wstring& xml, 
                        WideTools::eBOM endian)
        : _xml (xml), _endian (endian)
    {
        // Swap the endian-ness of our string if necessary
        // This is done in place!!
        if (_endian != WideTools::gOnly().endian())
            WideTools::gOnly().swap (_xml);

        // Remove any comments in the data
        std::wstring data;
        do {
            data = parseTag (L"<!--", L"-->");
        } while (!data.empty());

        // Remove any declarations in the data
        do {
            data = parseTag (L"<?", L"?>");
        } while (!data.empty());
    }


    std::wstring XMLTools::parseNextTag ()
    {
        // Find the start of the next tag
        size_t p1 = _xml.find (L"<");
        if (p1 == std::wstring::npos) {
            _xml = L"";
            return L"";
        }

        // Find the end of the tag
        size_t p2 = _xml.find (L">", p1);
        if (p2 == std::wstring::npos) {
            _xml = L"";
            return L"";
        }

        // Extract the tag and move the string
        std::wstring tag = _xml.substr (p1, p2-p1+1);
        _xml = _xml.substr (p2+1);

        return tag;
    }


    std::wstring XMLTools::parseNextEndTag (std::wstring tag)
    {
        // Convert this to an end tab (i.e. <tag> => </tag>)
        tag.insert (1, L"/");

        // Fetch everything up to the tag
        size_t p1 = _xml.find (tag);
        if (p1 == std::wstring::npos) {
            _xml = L"";
            return L"";
        }

        std::wstring contents = _xml.substr (0, p1);
        _xml = _xml.substr (p1 + tag.size());

        return contents;
    }


    std::wstring XMLTools::parseTag (const std::wstring& start, 
                                     const std::wstring& stop)
    {
        // Find the start tag
        size_t p1 = _xml.find (start);
        if (p1 == std::wstring::npos)
            return L"";

        // Find the stop tag
        size_t p2 = _xml.find (stop);
        if (p2 == std::wstring::npos)
            return L"";

        std::wstring contents = _xml.substr (p1, p2+stop.size()-p1);
        std::wstring pre, post;
        if (p1 > 0)
            pre = _xml.substr (0, p1);
        post = _xml.substr (p2+stop.size());
        _xml = pre + post;

        return contents;
    }


    XMLElement XMLTools::parse ()
    {
        XMLElement element;

        element.name    = parseNextTag ();
        if (!element.name.empty())
            element.value = parseNextEndTag (element.name);

        return element;
    }


    void XMLTools::writeResource (unsigned int id,
                                  const std::wstring& str,
                                  const std::wstring& notes)
    {
        if (_xml.empty()) {
            // Write the BOM
            _xml.push_back (WideTools::gOnly().bom());
            _xml += L"<?xml version=\"1.0\" encoding=\"UTF-16\" ?>\n<resources>\n";
        }

        char idstring[32];
        sprintf (idstring, "%d", id);
        std::wstring widstring;
        for (unsigned int i=0; i<strlen(idstring); i++)
            widstring += idstring[i];

        _xml += L"<phrase><id>" + widstring;
        _xml += L"</id><string>" + str + L"</string>";
        if (!notes.empty())
            _xml += L"<notes>" + notes + L"</notes>";
        _xml += L"</phrase>\n";
    }

    void XMLTools::writeTrailing ()
    {
        _xml += L"</resources>\n";
    }
}